﻿/* PRQA S 3108++ */
/**
 * Copyright (C) 2024 Isoft Infrastructure Software Co., Ltd.
 * SPDX-License-Identifier: LGPL-2.1-only-with-exception OR  LicenseRef-Commercial-License
 *
 * This library is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; version 2.1.
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License along with this library;
 * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 * or see <https://www.gnu.org/licenses/>.
 *
 * Alternatively, this file may be used under the terms of the Isoft Infrastructure Software Co., Ltd.
 * Commercial License, in which case the provisions of the Isoft Infrastructure Software Co., Ltd.
 * Commercial License shall apply instead of those of the GNU Lesser General Public License.
 *
 * You should have received a copy of the Isoft Infrastructure Software Co., Ltd.  Commercial License
 * along with this program. If not, please find it at <https://EasyXMen.com/xy/reference/permissions.html>
 *
 ********************************************************************************
 **                                                                            **
 **  FILENAME    : sm2_common.h                                                **
 **                                                                            **
 **  Created on  :                                                             **
 **  Author      : For the world peace                                         **
 **  Vendor      :                                                             **
 **  DESCRIPTION : implementation header for sm2 common                        **
 **                                                                            **
 **  SPECIFICATION(S) :   AUTOSAR classic Platform 4.4.0                       **
 **                                                                            **
 *******************************************************************************/
#ifndef peace_asn1_H
#define peace_asn1_H
/*******************************************************************************
**                      Includes                                              **
*******************************************************************************/
#include <time.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include "Std_Types.h"
#include "istd_lib.h"
/*******************************************************************************
**                      Global Symbols                                        **
*******************************************************************************/
#if __cplusplus
extern "C" {
#endif

/**
 * @brief ASN.1 tag constants.
 *
 * These constants define the ASN.1 tags used in the encoding and decoding of ASN.1 types.
 */
enum peace_asn1_TAG
{
    peace_asn1_TAG_BOOLEAN = 1,       /**< Boolean type tag. */
    peace_asn1_TAG_INTEGER = 2,       /**< Integer type tag. */
    peace_asn1_TAG_OCTET_STRING = 4,  /**< Octet string type tag. */
    peace_asn1_TAG_SEQUENCE = 0x30,   /**< Sequence type tag. */
};


/**
 * @brief Constants for SM3 hash algorithm.
 *
 * These constants define the digest size, block size, and state words for the SM3 hash algorithm.
 */
#define peace_sm3_DIGEST_SIZE 32     /**< Size of the SM3 digest in bytes. */
#define peace_sm3_BLOCK_SIZE 64      /**< Size of the SM3 block in bytes. */
#define peace_sm3_STATE_WORDS 8      /**< Number of 32-bit words in the SM3 state. */
/**
 * @brief Error codes.
 *
 * These constants define the error codes used in the library.
 */
#define E_ERROR -1     /**< Specific error. */

/**
 * @brief Macro to get a 32-bit unsigned integer from a byte array.
 *
 * This macro extracts a 32-bit unsigned integer from a big-endian byte array.
 *
 * @param p Pointer to the byte array.
 * @return 32-bit unsigned integer.
 */
#define GETU32(p)             \
    ((uint32)(p)[0] << 24 | \
     (uint32)(p)[1] << 16 | \
     (uint32)(p)[2] << 8 |  \
     (uint32)(p)[3])

/**
 * @brief Macro to put a 32-bit unsigned integer into a byte array.
 *
 * This macro writes a 32-bit unsigned integer into a big-endian byte array.
 *
 * @param p Pointer to the byte array.
 * @param V 32-bit unsigned integer to be written.
 */
#define PUTU32(p, V)                \
    ((p)[0] = (uint8)((V) >> 24), \
     (p)[1] = (uint8)((V) >> 16), \
     (p)[2] = (uint8)((V) >> 8),  \
     (p)[3] = (uint8)(V))

/**
 * @brief Macro to rotate a 32-bit unsigned integer.
 *
 * This macro rotates a 32-bit unsigned integer by a specified number of bits.
 *
 * @param a 32-bit unsigned integer to be rotated.
 * @param n Number of bits to rotate.
 * @return Rotated 32-bit unsigned integer.
 */
#define ROL32(a, n) (((a) << (n)) | (((a) & 0xffffffff) >> (32 - (n))))

/**
 * @brief Macro to rotate a 64-bit unsigned integer.
 *
 * This macro rotates a 64-bit unsigned integer by a specified number of bits.
 *
 * @param a 64-bit unsigned integer to be rotated.
 * @param n Number of bits to rotate.
 * @return Rotated 64-bit unsigned integer.
 */
#define ROL64(a, n) (((a) << (n)) | ((a) >> (64 - (n))))

/**
 * @brief Universal tag class.
 *
 * This constant defines the universal tag class in ASN.1.
 */
#define peace_asn1_TAG_UNIVERSAL 0x00

/**
 * @brief Content-specific tag class.
 *
 * This constant defines the content-specific tag class in ASN.1.
 */
#define peace_asn1_TAG_CONTENT_SPECIFIC 0x80

/**
 * @brief Constructed tag class.
 *
 * This constant defines the constructed tag class in ASN.1.
 */
#define peace_asn1_TAG_CONSTRUCTED 0x20

/**
 * @brief Macro to convert an integer to DER format.
 *
 * This macro converts an integer to its DER-encoded representation with the specified ASN.1 tag.
 *
 * @param d Pointer to the input buffer containing the integer data.
 * @param dlen Length of the input data buffer in bytes.
 * @param out Pointer to the output buffer where the encoded data will be written.
 * @param outlen Pointer to the variable storing the length of the output buffer.
 *               On successful return, it contains the actual length of the encoded data.
 */
#define peace_asn1_integer_to_der(d, dlen, out, outlen) peace_asn1_integer_to_der_ex(peace_asn1_TAG_INTEGER, d, dlen, out, outlen)

/**
 * @brief Macro to decode an integer from DER format.
 *
 * This macro decodes an integer from its DER-encoded representation with the specified ASN.1 tag.
 *
 * @param d Pointer to the input buffer containing the integer data.
 * @param dlen Length of the input data buffer in bytes.
 * @param in Pointer to the input buffer containing the encoded data.
 * @param inlen Pointer to the variable storing the length of the input buffer.
 *              On successful return, it contains the actual length of the decoded data.
 */
#define peace_asn1_integer_from_der(d, dlen, in, inlen) peace_asn1_integer_from_der_ex(peace_asn1_TAG_INTEGER, d, dlen, in, inlen)

/**
 * @brief Macro to convert an octet string to DER format.
 *
 * This macro converts an octet string to its DER-encoded representation with the specified ASN.1 tag.
 *
 * @param d Pointer to the input buffer containing the octet string data.
 * @param dlen Length of the input data buffer in bytes.
 * @param out Pointer to the output buffer where the encoded data will be written.
 * @param outlen Pointer to the variable storing the length of the output buffer.
 *               On successful return, it contains the actual length of the encoded data.
 */
#define peace_asn1_octet_string_to_der(d, dlen, out, outlen) peace_asn1_type_to_der(peace_asn1_TAG_OCTET_STRING, d, dlen, out, outlen)
/**
 * @brief Macro to decode an octet string from DER format.
 *
 * This macro decodes an octet string from its DER-encoded representation with the specified ASN.1 tag.
 *
 * @param d Pointer to the input buffer containing the octet string data.
 * @param dlen Length of the input data buffer in bytes.
 * @param in Pointer to the input buffer containing the encoded data.
 * @param inlen Pointer to the variable storing the length of the input buffer.
 *              On successful return, it contains the actual length of the decoded data.
 */
#define peace_asn1_octet_string_from_der(d, dlen, in, inlen) peace_asn1_type_from_der(peace_asn1_TAG_OCTET_STRING, d, dlen, in, inlen)
/**
 * @brief Macro to encode a sequence header to DER format.
 *
 * This macro encodes a sequence header to its DER-encoded representation with the specified ASN.1 tag.
 *
 * @param dlen Length of the sequence data in bytes.
 * @param out Pointer to the output buffer where the encoded data will be written.
 * @param outlen Pointer to the variable storing the length of the output buffer.
 *               On successful return, it contains the actual length of the encoded data.
 */
#define peace_asn1_sequence_header_to_der(dlen, out, outlen) peace_asn1_header_to_der(peace_asn1_TAG_SEQUENCE, dlen, out, outlen)

/*******************************************************************************
**                      Global Data Types                                     **
*******************************************************************************/

/**
 * @brief Context structure for the SM3 hash algorithm.
 *
 * This structure holds the internal state of the SM3 hash algorithm during its computation.
 */
typedef struct
{
    uint32 digest[peace_sm3_STATE_WORDS];  /**< Intermediate hash values. */
    uint64_t nblocks;                  /**< Number of blocks processed. */
    uint8 block[peace_sm3_BLOCK_SIZE];     /**< Current block being processed. */
    uint32 num;                        /**< Number of bytes in the current block. */
} peace_sm3_CTX;


/**
 * @brief Decodes an integer from DER format.
 *
 * This function decodes an integer from its DER-encoded representation with the specified ASN.1 tag.
 * It reads the encoded data from the input buffer and returns the decoded data.
 *
 * @param tag ASN.1 tag of the integer to be decoded.
 * @param d Pointer to the pointer where the decoded data will be stored.
 * @param dlen Pointer to the variable storing the length of the decoded data.
 * @param in Pointer to the input buffer containing the encoded data.
 * @param inlen Pointer to the variable storing the length of the input buffer.
 *              On successful return, it contains the actual length of the decoded data.
 * @return Zero on success, non-zero error code on failure.
 */
int peace_asn1_integer_from_der_ex(int tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);



/**
 * @brief Converts an integer to DER-encoded format.
 *
 * This function converts an integer to its DER-encoded representation with the specified ASN.1 tag.
 * It allocates memory for the output buffer and returns the encoded data.
 *
 * @param tag ASN.1 tag to be used for encoding the integer.
 * @param d Pointer to the input buffer containing the integer data.
 * @param dlen Length of the input data buffer in bytes.
 * @param out Pointer to the pointer where the allocated output buffer will be stored.
 * @param outlen Pointer to the variable storing the length of the output buffer.
 *               On successful return, it contains the actual length of the encoded data.
 * @return Zero on success, non-zero error code on failure.
 */
int peace_asn1_integer_to_der_ex(int tag, const uint8_t *d, uint32_t dlen, uint8_t **out, uint32_t *outlen);

/**
 * @brief Encodes a header to DER format.
 *
 * This function encodes a header to its DER-encoded representation with the specified ASN.1 tag.
 * It allocates memory for the output buffer and returns the encoded data.
 *
 * @param tag ASN.1 tag to be used for encoding the header.
 * @param dlen Length of the data to be encoded.
 * @param out Pointer to the pointer where the allocated output buffer will be stored.
 * @param outlen Pointer to the variable storing the length of the output buffer.
 *               On successful return, it contains the actual length of the encoded data.
 * @return Zero on success, non-zero error code on failure.
 */
int peace_asn1_header_to_der(int tag, size_t dlen, uint8_t **out, size_t *outlen);

/**
 * @brief Initializes the SM3 context structure.
 *
 * This function initializes the given SM3 context structure for subsequent hash operations.
 * It sets up the internal state of the context to its initial values as per the SM3 algorithm specification.
 *
 * @param ctx Pointer to the SM3 context structure that needs to be initialized.
 */
void peace_sm3_Init(peace_sm3_CTX *ctx);

/**
 * @brief Updates the SM3 hash computation with additional data.
 *
 * This function processes the provided data and updates the hash value stored in the SM3 context.
 * It can be called multiple times with different data chunks to compute the hash of concatenated data.
 *
 * @param ctx Pointer to the SM3 context structure where the hash computation is ongoing.
 * @param data Pointer to the input data buffer containing the data to be hashed.
 * @param datalen Length of the input data buffer in bytes.
 */
void peace_sm3_update(peace_sm3_CTX *ctx, const uint8 *data, uint32 datalen);

/**
 * @brief Finalizes the SM3 hash computation and outputs the resulting hash value.
 *
 * This function completes the hash computation using any remaining data in the SM3 context's buffer
 * and writes the final hash value to the output buffer. After calling this function, the context is reset.
 *
 * @param ctx Pointer to the SM3 context structure containing the current hash state.
 * @param dgst Output buffer where the computed hash value will be written.
 *             The buffer must have a minimum size of peace_sm3_DIGEST_SIZE bytes.
 */
void peace_sm3_finish(peace_sm3_CTX *ctx, uint8 dgst[peace_sm3_DIGEST_SIZE]);

/**
 * @brief Compresses multiple blocks of data using the SM3 compression function.
 *
 * This function applies the SM3 compression function to the provided data blocks and updates the intermediate hash value.
 * It assumes that the data length is a multiple of the SM3 block size (64 bytes).
 *
 * @param digest Pointer to the array of eight 32-bit words representing the intermediate hash state.
 * @param data Pointer to the input data buffer containing the data blocks to be compressed.
 *             The buffer must contain a number of bytes that is a multiple of peace_sm3_BLOCK_SIZE.
 * @param blocks Number of 64-byte blocks contained in the input data buffer.
 */
void peace_sm3_compress_blocks(uint32 digest[8], const uint8 *data, uint32 blocks);

/**
 * @brief Decodes a type from DER format.
 *
 * This function decodes a type from its DER-encoded representation with the specified ASN.1 tag.
 * It reads the encoded data from the input buffer and returns the decoded data.
 *
 * @param tag ASN.1 tag of the type to be decoded.
 * @param d Pointer to the pointer where the decoded data will be stored.
 * @param dlen Pointer to the variable storing the length of the decoded data.
 * @param in Pointer to the input buffer containing the encoded data.
 * @param inlen Pointer to the variable storing the length of the input buffer.
 *              On successful return, it contains the actual length of the decoded data.
 * @return Zero on success, non-zero error code on failure.
 */
int peace_asn1_type_from_der(int tag, const uint8 **d, size_t *dlen, const uint8 **in, size_t *inlen);
/**
 * @brief Converts a type to DER format.
 *
 * This function converts a type to its DER-encoded representation with the specified ASN.1 tag.
 * It allocates memory for the output buffer and returns the encoded data.
 *
 * @param tag ASN.1 tag to be used for encoding the type.
 * @param d Pointer to the input buffer containing the type data.
 * @param dlen Length of the input data buffer in bytes.
 * @param out Pointer to the pointer where the allocated output buffer will be stored.
 * @param outlen Pointer to the variable storing the length of the output buffer.
 *               On successful return, it contains the actual length of the encoded data.
 * @return Zero on success, non-zero error code on failure.
 */
int peace_asn1_type_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
/**
 * @brief Checks if one length is less than or equal to another.
 *
 */
static inline int peace_asn1_length_is_zero(uint32 len)
{
	if (len)
	{
		return E_ERROR;
	}
	return 1;
}

/**
 * @brief Evaluates an expression and asserts its truthiness.
 *
 */
static inline int peace_asn1_length_le(uint32 len1, uint32 len2)
{
	if (len1 > len2)
	{
		return E_ERROR;
	}
	return 1;
}
/**
 * @brief Evaluates an expression and asserts its truthiness.
 * 
 * This function evaluates the provided expression and asserts that it is true.
 * If the expression evaluates to false, the function triggers an assertion failure.
 * 
 * @param expr Expression to be evaluated.
 * @return     Zero if the expression is true, non-zero if the expression is false.
 */
int peace_asn1_check(int expr);

/**
 * @brief Performs bitwise XOR operation between two memory buffers and stores the result in another buffer.
 * 
 * This function performs a bitwise XOR operation between the contents of two source memory buffers
 * and stores the result in a destination memory buffer. The lengths of all three buffers must be equal.
 * 
 * @param r Pointer to the destination buffer where the XOR result will be stored.
 * @param a Pointer to the first source buffer.
 * @param b Pointer to the second source buffer.
 * @param len Length of the buffers in bytes.
 */
void peace_sm2_memxor(void *r, const void *a, const void *b, size_t len);

#if __cplusplus
}
#endif
#endif
